package com.example.shirodemo.framework.shiro.filter;

import com.alibaba.fastjson.JSONObject;
import com.demo.result.AjaxResult;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
import org.apache.shiro.web.util.WebUtils;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

/**
 * @Auther: SPL
 * @since: 2019-06-13 13:38
 * @Description: 自定义表单登录验证器，处理session时效跳转响应
 */
@Slf4j
public class SsoAuthFilter extends FormAuthenticationFilter {

    /**
     * 表示是否允许访问；mappedValue就是[urls]配置中拦截器参数部分，如果允许访问返回true，否则false；
     * <p>
     * 由于Shiro filterChainDefinitions中 roles默认是and， /admin= user,roles[system,general]
     * 比如：roles[system,general] ，表示同时需要“system”和“general” 2个角色（权限）才通过认证，缺一不可。
     * 但是在实际业务中，一个端口往往同时对几个角色开放。比如管理员账号拥有访问所有端口的权限。那么此时的and显然是不合时宜的，与之替代的是or
     * </p><br>
     * 在此处：CORS跨域请求有时发送请求时会预先发送一个OPTIONS请求,让它通过<br>
     *
     * @return
     */
    @Override
    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
        boolean allowed = super.isAccessAllowed(request, response, mappedValue);
        if (!allowed) {
            // 判断请求是否是options请求
            String method = WebUtils.toHttp(request).getMethod();
            if ("OPTIONS".equalsIgnoreCase(method)) {
                return true;
            }
        }
        return allowed;
    }

    /**
     * 表示当访问拒绝时执行此方法；如果返回true表示通过；如果返回false表示请求到此为止，响应即可。<br>
     * <p>
     * 在访问controller前判断是否登录，返回json，不进行重定向。
     *
     * @param request
     * @param response
     * @return true-继续往下执行，false-该filter过滤器已经处理，不继续执行其他过滤器
     * @throws Exception
     */
    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {

        //登录请求不处理
        if (this.isLoginRequest(request, response)) {
            if (this.isLoginSubmission(request, response)) {
                return this.executeLogin(request, response);
            } else {
                return true;
            }
        } else {
            AjaxResult result = AjaxResult.error(401,"您尚未登录或登录已过期，请先登录");
            String resStr = JSONObject.toJSONString(result);
            log.warn("响应：{}", resStr);
            response.setContentType("application/json");
            response.setCharacterEncoding("UTF-8");
            response.getWriter().print(resStr);
            return false;
        }
    }

}
